/**
 * BlogWidget Configuration
 * 1. Global widget configuration variables
 *
 * listonic_language - determins language of the widget, available options en, en_*, pl, pl_*, Polish is default
 * 
 * listonic_turnOff = true/false - enable or disable buttons
 *
 * listonic_bw_type - Blog Widget Type - {blogger, blox, bloog, generic} - determines current Blog System and use one of
 * the predefined settings
 *
 * listonic_includeTags - array of tags, widget process the post only when it is tagged with at least one of the supplied
 * tags
 * listonic_excludeTags - array of tags, widget skips the posts when it is tagged with at least one of the tags
 * listonic_firstOnly - boolean, aka listonic_tylkoPierwszy - if true only first ul in each post will be processed
 * listonic_minCount - integer, aka listonic_tylkoPierwszy - defines minimal number of elements in <ul> to consider it as
 * 					   a list of ingredients, default = 3
 * listonic_iframeWidth - width of the sidebar panel.
 * listonic_hideSideBar - boolean - aka listonic_ukryjPanelBoczny - if true disables presence in the sidebar 
 *
 *
 * 2. Generic Blog Widget Type config
 * Paramteres priorities are order according to their level of specificity
 * e.g. DOM node id - defines an element unambiguously - according to the html specification particular id should appear
 * only once in the html document, while class/tag may be used with numerous elements in the same document.
 * When id and class are both defined for the same element type - the id should always be used over the class
 * as an element indicator.
 *
 * 2.1 Posts Detection
 * -> Often time whole content section is contained in some sort of wrapper. It separates the blog content from headers,
 * -> footers and side pannels.
 * -> Disovering such wrapper allows to narrow the search area. Following parameters allow to define such wrapper.
 *
 * listonic_bw_generic_contentId - id of the main column (contains all the entries)
 * listonic_bw_generic_contentClass - css class of the main column //TODO: implement
 * listonic_bw_generic_contentTag - element tag used to define main column //TODO: implement
 *
 *
 * listonic_bw_generic_contentAsEntry - (default=false) - treat main column content as the whole entry
 *		comment - used in one case for a single entry view (single entry on page,without a further structure inside)
 *
 * -> Following parameter allow to discover entry wrapper. It may contain footer, header and entry content depending on
 * -> the blog platform.
 *
 * listonic_bw_generic_entryClass - css class of the single entry wrapper
 * listonic_bw_generic_entryTag - tag of the single entry wrapper
 *
 * 2.2 Post Processing
 * 2.2.1 Post Content
 * -> Following paramters are used to indicate the entry contnet inside the entry wrapper.
 * -> When not defined a whole contnet of the entry wrapper is used.
 *
 * listonic_bw_generic_entryContentClass - css class of element containing entry/post content
 * listonic_bw_generic_entryContentTag - tag of element containing entry/post content
 *
 * 2.2.2 Post Header
 * -> Post may have header conatining information like title, url etc. we would like to extract.
 * -> Following parameters define the header element
 *
 * listonic_bw_generic_entryHeaderClass - css class of the header wrapper
 * listonic_bw_generic_entryHeaderTag - tag of the header wrapper
 *
 * -> Parameters indicating entry title.
 *
 * listonic_bw_generic_entryHeaderTitleClass - css class of the entry title
 * listonic_bw_generic_entryHeaderTitleTag - tag of the entry title
 *
 * -> Following parameter allow to extract the entry url - desierably leading to the single post view
 *
 * listonic_bw_generic_entryHeaderUrlWrapperClass - css class of url wrapper
 * listonic_bw_generic_entryHeaderUrlWrapperTag - ta of the url wrapper
 *
 * listonic_bw_generic_entryHeaderUrlClass - css class of the url tag is always <A>
 *											 when no class provided search by tag is applied
 *
 * 2.2.3 Post Footer
 * -> Post footer may contain some specific information about post we would like to extract.
 * -> E.g. tags, url ...
 * -> Following paramerts define the footer element
 *
 * listonic_bw_generic_entryFooterClass - css class of the footer wrapper
 * listonic_bw_generic_entryFooterTag - tag of the footer wrapper
 *
 * //use only when not defined in the header
 *
 * listonic_bw_generic_entryFooterUrlWrapperClass - css class of the url wrapper
 * listonic_bw_generic_entryFooterUrlWrapperTag - tag of the url wrapper
 *
 * listonic_bw_generic_entryFooterUrlClass - css class of the url tag is always <A>
 *											 when no class provided search by tag is applied
 *
 *
 * 2.3 Other
 *
 * listonic_bw_generic_validateULs - function applied to the ULs found in the post.
 * @return true - when ul is valid ingredients list, false when ul is not valid ingredients list
 * E.g. moje wypieki blog.
 *
 * listonic_bw_generic_getTags - custom function to extract tags for entry
 * @return array of tags 
 */


/**
 * BlogWidget Configuration
 * 1. Global ustawienia widgeta
 *
 * listonic_turnOff = true/false - włącza lub wyłącza przyciski
 *
 * listonic_bw_type - typ widgeta {blogger, blox, bloog, generic} - deklaracja platformy blogowej pozwala na używanie predifionwanych ustawień
 *
 * listonic_includeTags - array of tags, widget procesuje jedynie posty oznaczone co najmniej jeden z wymienionych tagów
 * listonic_excludeTags - array of tags, widget nie procesuje postów oznaczonych co najmniej jednym z wymienionych tagów
 * listonic_firstOnly - boolean, aka listonic_tylkoPierwszy - jeśli true tylko pierwszy <ul> w danym poście jest przetwarzany
 * listonic_minCount - integer, aka listonic_tylkoPierwszy - minimalna ilość elementów w liście <ul> dla której dodawny jest przycisk, default = 3
 * listonic_iframeWidth - szerokośc widgetu w panelu bocznym
 * listonic_hideSideBar - boolean - aka listonic_ukryjPanelBoczny - jeśli true nie generuj widgetu w panelu bocznym 
 *
 *
 * 2. Konfiguracja widgeta w trybie pracy GENERIC
 * Prioryteyzacja parametrów zgodna jest z dokładnością definiowanych przez nie elemnety
 * n.p. DOM node id - wskazuje element jednoznacznie - zgodnie ze specyfikacją HTML w dokumencie powinien znajdować się dokładnie jeden 
 * element o określonym id, elementy określane przez class/tag mogą wsytępować wielokrotnie w całym dokumencie
 * Gdy dla wskazania danego rodzaju elementów zdefiniowane są zarówno id or class/tag wówczas element wskazany przez id zostanie 
 * użyty dla celów procesowania.
 *
 * 2.1 Wykrywanie Postów/Wpisów
 * -> Bardzo często treść bloga opakowana jest w jeden element DOM, dzięki czemy może zostać skutecznie odseparowany od 
 * -> headerów, footerów czy sidebarów. 
 * -> Korzystając z tego możemy zawęzić obszar procesowania, unikając umieszczania przycisku w nieodpowiedniej sekcji.
 *
 * listonic_bw_generic_contentId - id głównej kolumny z treścią - zawierającej wszystkie wpisy
 * listonic_bw_generic_contentClass - klasa wskazująca główną kolumnę //TODO: implement
 * listonic_bw_generic_contentTag - tag kolumny głównej //TODO: implement
 *
 *
 * listonic_bw_generic_contentAsEntry - (default=false) - treat main column content as the whole entry
 *		comment - used in one case for a single entry view (single entry on page,without a further structure inside)
 *
 * -> Poniższe patametry definiują element opakowujący pojedynczy wpis. Najczęściej zawiera w sobie header wpisu, footer wpisu 
 * -> w zależności od platfromy blogowej.
 *
 * listonic_bw_generic_entryClass - klasa wskazująca element opakowujący pojedynczy wpis
 * listonic_bw_generic_entryTag - tag elementu opakowującego pojedynczy wpis
 *
 * 2.2 Przetwarzanie Postów/Wpisów
 * 2.2.1 Treść Wpisu
 * -> Poniższy pametr pozwala na wskazanie treści wpisu wewnątrz elementu opakowującego.  
 * -> Jeśli nie jest zdefiniowany wówczas cała zawartość wprapper jest procesowana jako treść wpisu.
 *
 * listonic_bw_generic_entryContentClass - klasa elementu zawierającego treść wpisu 
 * listonic_bw_generic_entryContentTag - tag elementu zawierającego treść wpisu
 *
 * 2.2.2 Header Wpisu
 * -> Nagłówki wpisu często zawierają informacje o tytule, adresie url itp. które chcemy wydobyć
 *
 * listonic_bw_generic_entryHeaderClass - klasa nagówka wpisu
 * listonic_bw_generic_entryHeaderTag - tag nagłówka wpisu
 *
 * -> Poniższe parametry pozwalają na wskzanie elementu zaiwerającego tytuł wpisu
 *
 * listonic_bw_generic_entryHeaderTitleClass - klasa elementu zawierającego tytuł wpisu
 * listonic_bw_generic_entryHeaderTitleTag - tag elementu zawierającego tytuł wpisu
 *
 * -> Pniższe patametry definiują element zawierający adres URL - najlepiej aby prowadził on do widoku pojedynczego wpisu
 *
 * listonic_bw_generic_entryHeaderUrlWrapperClass - klasa wskazująca na wraper adresu
 * listonic_bw_generic_entryHeaderUrlWrapperTag - tag wskazujący na wraper adresu
 *
 * listonic_bw_generic_entryHeaderUrlClass - klasa elementu zawierającego adres url wpisu tag to zawsze <A>
 *											 jeśli klasa nie jest zdefiniowana wówczas następuje wyszukiwanie po samym tagu
 *
 * 2.2.3 Post Footer
 * -> Stoka wpisu często zawiera informacje które chcielibyśmy wydobyć n.p. tagi, adres url
 *
 * listonic_bw_generic_entryFooterClass - klasa stopki wpisu
 * listonic_bw_generic_entryFooterTag - tag stopki wpisu
 *
 * //poniższe parametry są używane jedynie gdy odpowiadające parametry nie zostały zdefiniowane dla nagłówka
 *
 * listonic_bw_generic_entryFooterUrlWrapperClass - klasa wskazująca na wraper adresu
 * listonic_bw_generic_entryFooterUrlWrapperTag - tag wskazujący na wraper adresu
 *
 * listonic_bw_generic_entryFooterUrlClass - klasa elementu zawierającego adres url wpisu tag to zawsze <A>
 *											 jeśli klasa nie jest zdefiniowana wówczas następuje wyszukiwanie po samym tagu
 *
 *
 * 2.3 Other
 *
 * listonic_bw_generic_validateULs - funkcja wywoływana dla celu zwalidownia poprawności znalezionych elementów <ul> we wpisie
 * @return true - gdy ul zawiera składniki przepisu, false gdy ul nie zawiera składników przepisu (wyrzucany jest z dalszego przetwarzania)
 * E.g. moje wypieki blog.
 *
 * listonic_bw_generic_getTags - funkcja wydobywająca listę tagów z wpisu
 * @return array of tags 
 */



/**TextProcessor Configuration
 * 
 * listonic_tp_useWholeText - default false - specific case when entry content contains only ingredients in the textual form
 * 
 */


/** Konfiguracja TextProcessora
 * 
 * listonic_tp_useWholeText - default false - specyficzny przypadek gdy wyodręniona treść wpisu zawiera wyłącznie składniki w formie tekstowej
 * 
 */


/**
 * removes all the empty characters form the begining and the end of the sring str
 * @param {string} str - string to process
 */
function ListonicTrim(str) {
	var trimmed = str

	if(trimmed) {
		trimmed = trimmed.replace(/^\s+|\s+$/g, '');
	}

	return trimmed;
}

/**
 * estimatest number of words in the string
 * @param {string} str
 */
function ListonicWC(str) {
	var wcregex = /(^|\s)[^\s]+?(?=\s|$)/ig;

	var matches = str.match(wcregex);

	if(matches) {
		return matches.length;
	} else {
		return 0;
	}
}

/**
 * module used to process the blog content - used when DOM structure is not sufficient to recognize recipie's ingredients
 * @param {}
 */
function ListonicBlogContentsProcessor(blogentry) {
	// 	Congiguration section

	/**
	 * regex used to find Ingredients List Header
	 */
	this._IngredientsRegex = /(składnik|produkty|ingredient)/ig;
	/*
	 * reges used to find Intstrctions List/Description Header - indication often end of ingredients list
	 */
	this._InstructionsRegex = /(wykonanie|instruk|przygotowani|instruction|direction|preparation)/ig;
	/**
	 * regex used to recognize bullet pattern in the ingredient lists
	 * modify when need to change this behaviour
	 */
	this._BulletRegex = /^\s*(-|\+|•|·)\s*/ig;

	/**
	 * max distance in lines between two bulleted items used for grouping purposes
	 * allows section titles in between bulleted items
	 * prevents from grouping bulleted items separated by a large paragraph of text.
	 */
	this.IngredientBulletMaxDistance = 3;

	/**
	 * max word count for a section title between
	 */
	this.SectionNameMaxWC = 5;
	//wc = word count

	//	Processing Section
	this.BlogEntryOriginal = blogentry;

	this.BlogEntry = blogentry;

	this.HasIngridientsHeader = false;

	this.EntryText = "";

	this.SplittedEntryText = null;
	this.SplittedEvaluation = new Array();

	this.Lists = new Array();

	//zmienne sterujące
	this.useWholeText = false;

	this.Init = function() {
		if(this.isdefined('listonic_tp_useWholeText')) {
			this.useWholeText = listonic_tp_useWholeText;
		}
	};

	this.process = function() {

		//najpierw operujemy na oryginalnym elemnecie z drzewa DOM
		this.BlogEntry = this.BlogEntryOriginal;

		//new line characters - /n - are inserted for better text format recogniton
		// - eg. putting <br /> doesn't generate new line character in all browsers
		//new line characters need to be inserted in the original DOM tree otherwise it is not visible for IE
		//white characters we add does not affect the way particular HTML is rendered
		this.getEntryText();

		this.BlogEntry = this.BlogEntryOriginal.cloneNode(true);

		this.HasIngridientsHeader = this.hasIngredients();

		if(this.useWholeText) {

			this.splitEntryText();

			this.clearSplittedText();

			this.discoverListsWholeText();

			this.getNodes();

		} else {
			if(this.HasIngridientsHeader) {
				//dzieli tekst na linie
				this.splitEntryText();

				//usuwa zbędne puste linie
				this.clearSplittedText();

				//wykrywa gdzie zaczynają się skłaniki (tekst zawierający słowo składniki lub podobne_
				this.evalIngredients();

				//szuka wypunktowań
				this.evalBullet();

				//szacuje grupy wypunktowanych elementów
				this.evalBulletGroupSize();

				//wykrywa listy składników podzielonych na sekcje
				this.discoverListsWithSections();

				//wyszukuje odpowiednie nody w drzewie dom niezbędne do wstawienia buttonów
				this.getNodes();
			}

		}
	};

	this.processUlsGrouping = function(uls) {
		var result = new Array();
		var UUID = new Array();
		var entryClone = null;

		var UlsEvaluation = new Array();

		var onErrorRollback = false;

		var clonedUls = new Array();

		if(uls && uls.length > 1) {

			for(var i = 0; i < uls.length; i++) {
				//add classes
				UlsEvaluation[i] = new Object();

				UlsEvaluation[i].UUID = this.randomUniqueString(this.BlogEntry.innerHTML);

				if(UlsEvaluation[i].UUID == null) {
					//TODO: rollback
					alert("Error");
					onErrorRollback = true;
					break;
				}

				uls[i].className += " " + UlsEvaluation[i].UUID;

			}

			//clone
			entryClone = this.BlogEntry.cloneNode(true);

			for(var i = 0; i < uls.length; i++) {
				//remove classes
				if(UlsEvaluation[i].UUID) {
					var regexp = new RegExp("\s*" + UlsEvaluation[i].UUID + "$", "ig");
					uls[i].className = uls[i].className.replace(regexp, "");
					//console.log(uls[i]);
				}

				if(!onErrorRollback) {
					var elements = this.getElementsByClassNameL(UlsEvaluation[i].UUID, entryClone, "ul");

					if(elements && elements.length > 0) {
						clonedUls[i] = elements[0];
						//add texts - pre and post
						this.insertAfter(clonedUls[i], document.createTextNode(UlsEvaluation[i].UUID));
						this.insertBefore(clonedUls[i], document.createTextNode(UlsEvaluation[i].UUID));
					}
				}
			}

			if(onErrorRollback) {
				return null;
			}

			//inner text
			entryClone.innerHTML = this.preprocessHTML(entryClone.innerHTML);
			var EntryText = this.parseHTMLForText(entryClone);

			//eval groups

			for(var i = 0; i < clonedUls.length - 1; i++) {
				//get text between	ul[i] and ul[i+1]
				//console.log(EntryText);

				var firstIndex = this.getFirstInstanceIndex(EntryText, UlsEvaluation[i + 1].UUID);
				var lastIndex = this.getLastInstanceIndex(EntryText, UlsEvaluation[i].UUID);

				if(firstIndex > 0 && lastIndex > 0) {
					var substring = EntryText.substring(firstIndex, lastIndex);
					//console.log(substring);
					var hasValidSectionName = this.isValidSectionNameMultiline(substring);

					if(hasValidSectionName) {
						//sprawdź czy [i] należy do grupy
						if(UlsEvaluation[i].groupingFirstElement || UlsEvaluation[i].groupingElement) {

						} else {
							UlsEvaluation[i].groupingFirstElement = true;
							UlsEvaluation[i].groupingElement = true;
						}
						//nie to oznacz go jako początek grupy a [i+1] jako element grupy
						//tak to oznacz [i+1] jako element grupy
						UlsEvaluation[i + 1].groupingElement = true;

						//jeśli ostatni element listy oznacz jako ostatni element grupy
						if(i + 1 == clonedUls.length - 1) {
							UlsEvaluation[i + 1].groupingLastElement = true;
						}

					} else {
						//jeśli [i] jest wewnątrz grupy oznacz go jako ostatni z grupy
						if(UlsEvaluation[i].groupingElement) {
							UlsEvaluation[i].groupingLastElement = true;
						}
					}

				} else {
					if(UlsEvaluation[i].groupingElement) {
						UlsEvaluation[i].groupingLastElement = true;
					}
					continue;
				}
			}

		}
		result = this.ulsToGroupedForm(uls, UlsEvaluation);
		//console.log(result);
		return result;
	};

	this.ulsToGroupedForm = function(uls, UlsEvaluation) {
		var result = new Array();
		var iterator = 0;
		var inGroup = false;
		for(var i = 0; i < uls.length; i++) {

			if(UlsEvaluation[i] && UlsEvaluation[i].groupingElement) {
				if(UlsEvaluation[i].groupingFirstElement) {
					result[iterator] = new Array();
					result[iterator].push(uls[i]);
					inGroup = true;
				} else if(UlsEvaluation[i].groupingLastElement) {
					result[iterator].push(uls[i]);
					iterator++;
					inGroup = false;
				} else {
					result[iterator].push(uls[i]);
				}
			} else {
				result[iterator] = new Array();
				result[iterator].push(uls[i]);
				iterator++;
			}

		}

		return result;
	};

	this.isValidSectionNameMultiline = function(str) {
		var SplittedText = str.split("\n");
		//console.log(SplittedText);
		SplittedText = this._clearSplittedText(SplittedText);
		//console.log(SplittedText);

		var sectionNameDiscovered = false;

		for(var i = 0; i < SplittedText.length; i++) {
			if(SplittedText[i] && SplittedText[i].length > 0) {
				if(this.isValidSectionName(SplittedText[i])) {
					if(!sectionNameDiscovered) {
						sectionNameDiscovered = true;
					} else {
						return false;
					}
				} else {
					return false;
				}
			}
		}
		return true;
	};

	this.getFirstInstanceIndex = function(str, query) {
		var reg = new RegExp(query, "g");
		var match = reg.exec(str);
		if(match != null) {
			return match.index;
		}
		return -1;
	};

	this.getLastInstanceIndex = function(str, query) {
		var reg = new RegExp(query, "g");
		var match = reg.exec(str);
		var result = -1;
		while(match != null) {
			result = match.index + query.length;
			match = reg.exec(str);
		}

		return result;
	};

	this.getEntryText = function() {
		//TODO: fix so it doesn't affect live HTML
		this.BlogEntry.innerHTML = this.preprocessHTML(this.BlogEntry.innerHTML);
		/*this.BlogEntry =*/
		this.preprocessDIVs(this.BlogEntry);
		this.EntryText = this.parseHTMLForText(this.BlogEntry);
		return this.EntryText;
	};

	this.preprocessHTML = function(innerhtml) {
		var result = innerhtml.replace(/<br\s*\/?>(?!=\\n)/ig, "<br \/>\n");
		return result;
	};
	//TODO: zweryfikować czy potrzebne
	this.preprocessDIVs = function(elem) {
		var elements = elem.getElementsByTagName('div');
		var textNode = document.createTextNode("\n");
		
		for(var i = 0; i < elements.length; i++) {
			//
			try{
			if(elements[i] && (!elements[i].style.display || elemenst[i].style.display == 'block') && (!elements[i].style.cssFloat || elements[i].style.cssFloat == 'none')) {
				this.insertAfter(elements[i], textNode.cloneNode(true));
			}
			}catch(err){}
		}
		
	};

	this.splitEntryText = function() {
		this.SplittedEntryText = this.EntryText.split("\n");
		return this.SplittedEntryText;
	};

	this.clearSplittedText = function() {
		var result = this._clearSplittedText(this.SplittedEntryText);
		return result;
	};

	this._clearSplittedText = function(strArray) {
		var result = new Array();
		for(var i = 0; i < strArray.length; i++) {
			var buf = ListonicTrim(strArray[i]);
			//if (buf && buf.length>=0){
			result.push(buf);
			//}
		}
		this.SplittedEntryText = result;
		return result;
	};

	this.getNodes = function() {
		var text = this.EntryText;
		var rowindex = -1;
		rowindex = this._nextNonemptyRowIndex(rowindex);

		var lastindex = 0;
		var lastlength = 0;
		var items = null;

		while(rowindex != null) {
			var nodetext = this.SplittedEntryText[rowindex];
			lastindex = text.indexOf(nodetext, lastindex + lastlength);
			lastlength = nodetext.length;

			if(this.SplittedEvaluation[rowindex].firstElement) {
				items = new Array();

			}

			if(this.SplittedEvaluation[rowindex].listElement) {
				items.push(this.clearItem(this.SplittedEntryText[rowindex]));
			}

			if(this.SplittedEvaluation[rowindex].lastElement) {

				var instanceindex = this._getInstanceIndex(text, nodetext, lastindex);

				var nodes = this.getLastNode(this.BlogEntryOriginal, nodetext);

				var node = this._reverseNodeCrawl(nodes[instanceindex]);

				this.SplittedEvaluation[rowindex].topNode = node;
				this.SplittedEvaluation[rowindex].bottomNode = nodes[instanceindex];

				var list = new Object();

				list.items = items;
				list.lastNode = node;

				this.Lists.push(list);
			}
			rowindex = this._nextNonemptyRowIndex(rowindex);
		}
	};

	this._getInstanceIndex = function(text, query, index) {
		var tempindex = -1;
		var instanceindex = -1;
		var nextstart = 0;
		var qlength = query.length;
		do {
			tempindex = text.indexOf(query, nextstart);
			if(tempindex != -1) {
				instanceindex++;
			}
			nextstart = tempindex + qlength;
		} while(tempindex != -1 && tempindex != index )

		return instanceindex;
	};

	this._nextNonemptyRowIndex = function(rowindex) {
		rowindex++;
		while(rowindex < this.SplittedEntryText.length) {
			if(this.SplittedEntryText[rowindex].length > 0) {
				return rowindex;
			}
			rowindex++;
		}
		return null;
	};

	this.getLastNode = function(rootNode, lastnodeText) {
		var text = this.parseHTMLForText(rootNode);
		var index = text.indexOf(lastnodeText);

		var lastnode = new Array();
		if(index >= 0) {
			for(var i = 0; i < rootNode.childNodes.length; i++) {
				var temp = this.getLastNode(rootNode.childNodes[i], lastnodeText);
				if(temp.length > 0) {
					if(lastnode.length == 0) {
						lastnode = temp;
					} else {
						lastnode = lastnode.concat(temp);
					}
				}
			}

			if(lastnode.length == 0) {
				lastnode.push(rootNode);
				//console.log(lastnode);
				//console.log("nodeeper");
			}
		}
		return lastnode;
	};

	this.crawlBackNodes = function(nodes) {
		var result = new Array();
		if(nodes) {
			for(var i = 0; i < nodes.length; i++) {
				result.push(this._reverseNodeCrawl(nodes[i]));
			}
		}
		return result;
	};

	this._reverseNodeCrawl = function(node) {
		var t1 = ListonicTrim(this.parseHTMLForText(node));
		var t2 = ListonicTrim(this.parseHTMLForText(node.parentNode));
		if(t1 == t2) {
			return this._reverseNodeCrawl(node.parentNode);
		} else {
			return node;
		}
	};

	this.hasIngredients = function() {
		var hasmatch = (this.EntryText).match(this._IngredientsRegex);

		if(hasmatch != null) {
			return true;
		} else {
			return false;
		}
	};

	this.evalRegex = function(regex, property) {
		for(var i = 0; i < this.SplittedEntryText.length; i++) {
			var hasmatch = this.SplittedEntryText[i].match(regex);

			if(this.SplittedEvaluation[i] == undefined) {
				this.SplittedEvaluation[i] = new Object();
			}

			if(hasmatch != null) {
				//console.log(property);
				//console.log(this.SplittedEntryText[i]);
				this.SplittedEvaluation[i][property] = true;
			} else {
				this.SplittedEvaluation[i][property] = false;
			}
		}
	};

	this.discoverListsWholeText = function() {

		var discoverLastElementMode = false;
		var lastElementIndex = -1;

		for(var i = 0; i < this.SplittedEntryText.length; i++) {

			if(this.SplittedEvaluation[i] == undefined) {
				this.SplittedEvaluation[i] = new Object();
			}

			var buf = this.SplittedEntryText[i];

			if(buf && buf.length >= 0) {
				lastElementIndex = i;
				if(discoverLastElementMode == false) {
					discoverLastElementMode = true;
					this.SplittedEvaluation[i].firstElement = true;

				}
				this.SplittedEvaluation[i].listElement = true;
			}
		}

		if(discoverLastElementMode) {
			this.SplittedEvaluation[lastElementIndex].lastElement = true;
		}
	};

	this.discoverListsWithSections = function() {
		var firstIndex = -1;
		var ingredientsIndex = -1;
		var discoverFirstElementMode = false;
		var discoverLastElementMode = false;

		var ingredientsbulletdistance = -1;

		var lastElementIndex = -1;

		var sectionNameIndex = -1;
		var sectionNameFound = false;

		var includeSectionName = true;
		// TODO: zdaje się iż jest to nie używany parametr wywalić go z kodu
		//wcześniej dodawane były nazwy sekcji ale od kiedy działa kategoryzowanie produktów nie jest używane
		//gdyż ich kolejność i tak się zmienia i nazwy sekcji pojawiają się w randomowych miejscach

		for(var i = 0; i < this.SplittedEntryText.length; i++) {

			if(this.SplittedEvaluation[i].hasIngredients == true && this.SplittedEvaluation[i].hasBullet == false) {
				discoverFirstElementMode = true;
				ingredientsbulletdistance = 0;
				//start calculating distance;

				//zaraz po bulleted element następuje następne "składniki"

				//08-08-2011 http://www.slodkiefantazje.pl/
				//Problem gdy kilka razy pojawia się tekst składniki (jako Section Name)
				//TODO: Test the Impact of this Change
				//Solution: jeśli w nazwie jest składniki ale jest to validSectionName nie rozdzielaj na dwa przyciski
				if(discoverLastElementMode && !this.isValidSectionName(this.SplittedEntryText[i])) {
					discoverFirstElementMode = true;
					discoverLastElementMode = false;
					ingredientsbulletdistance = -1;
					//mark previous element as last
					if(lastElementIndex != -1) {
						this.SplittedEvaluation[lastElementIndex].lastElement = true;
					}
					lastElementIndex = -1;
				}
			} else {
				if(discoverFirstElementMode) {
					//inkrementuj distance jeśli potrzeba
					if(ingredientsbulletdistance > 0) {
						ingredientsbulletdistance++;
					}

					//sprawdź czy nie przekorczyliśmy maksymalnej odległości pomiędzy ingredients a bulleted items
					if(this.IngredientBulletMaxDistance > 0 && ingredientsbulletdistance > 0 && ingredientsbulletdistance > this.IngredientBulletMaxDistance) {
						discoverFirstElementMode = false;
						discoverLastElementMode = false;
						ingredientsbulletdistance = -1;
						lastElementIndex = -1;
						continue;
					}

					//jeśli jest bulleted oznacz jako pierwszy element listy
					if(this.SplittedEvaluation[i].hasBullet) {
						discoverFirstElementMode = false;
						discoverLastElementMode = true;
						ingredientsbulletdistance = -1;
						this.SplittedEvaluation[i].firstElement = true;
						this.SplittedEvaluation[i].listElement = true;
						lastElementIndex = i;
					} else if(this.isValidSectionName(this.SplittedEntryText[i])) {
						if(sectionNameFound) {
							//dwa razy section name found
							discoverFirstElementMode = false;
							discoverLastElementMode = false;
							ingredientsbulletdistance = -1;
							lastElementIndex = -1;
							sectionNameFound = false;
							sectionNameIndex = -1;

							continue;
						}
						sectionNameFound = true;
						sectionNameIndex = i;
					}

				} else if(discoverLastElementMode) {
					//jeśli nie bulleted i nie pusty oznacz jako ostatni element listy
					if(!this.SplittedEvaluation[i].hasBullet && this.SplittedEntryText[i] && this.SplittedEntryText[i].length > 0) {

						if(this.isValidSectionName(this.SplittedEntryText[i])) {
							if(sectionNameFound) {
								//dwa razy section name found
								discoverFirstElementMode = false;
								discoverLastElementMode = false;
								ingredientsbulletdistance = -1;
								lastElementIndex = -1;
								sectionNameFound = false;
								sectionNameIndex = -1;

								continue;
							}

							//console.log("true");
							sectionNameFound = true;
							sectionNameIndex = i;
						} else {
							discoverFirstElementMode = false;
							discoverLastElementMode = false;
							ingredientsbulletdistance = -1;
							if(lastElementIndex != -1) {
								this.SplittedEvaluation[lastElementIndex].lastElement = true;
							}
							lastElementIndex = -1;
						}

					} else if(this.SplittedEvaluation[i].hasBullet) {
						this.SplittedEvaluation[i].listElement = true;
						lastElementIndex = i;
						if(sectionNameFound) {
							//this.SplittedEvaluation[sectionNameIndex].listElement = true;
							sectionNameFound = false;
							sectionNameIndex = -1;

						}
					}

				}
			}

		}

		if(discoverLastElementMode) {
			//składniki są na samym końcu wpisu
			discoverFirstElementMode = false;
			discoverLastElementMode = false;
			if(lastElementIndex != -1) {
				this.SplittedEvaluation[lastElementIndex].lastElement = true;
			}
			lastElementIndex = -1;
		}
	};

	this.isValidSectionName = function(str) {

		if(str && str.length > 0) {
			//nie zawiera w sobie wykonanie
			var match = str.match(this._InstructionsRegex);

			if(match == null || match.length == 0) {
				//sprawdź czy nie przekracza max wc
				var wc = ListonicWC(str);

				if(wc <= this.SectionNameMaxWC) {
					return true;
				}
			}
		}
		return false;
	};

	this.discoverLists = function() {
		var firstIndex = -1;
		var ingredientsIndex = -1;
		var discoverFirstElementMode = false;
		var discoverLastElementMode = false;

		var ingredientsbulletdistance = -1;

		var lastElementIndex = -1;

		for(var i = 0; i < this.SplittedEntryText.length; i++) {

			if(this.SplittedEvaluation[i].hasIngredients == true && this.SplittedEvaluation[i].hasBullet == false) {
				discoverFirstElementMode = true;
				ingredientsbulletdistance = 0;
				//start calculating distance;

				//zaraz po bulleted element następuje następne "składniki"
				if(discoverLastElementMode) {
					discoverFirstElementMode = false;
					discoverLastElementMode = false;
					ingredientsbulletdistance = -1;
					//mark previous element as last
					if(lastElementIndex != -1) {
						this.SplittedEvaluation[lastElementIndex].lastElement = true;
					}
					lastElementIndex = -1;
				}
			} else {
				if(discoverFirstElementMode) {
					//inkrementuj distance jeśli potrzeba
					if(ingredientsbulletdistance > 0) {
						ingredientsbulletdistance++;
					}

					//sprawdź czy nie przekorczyliśmy maksymalnej odległości pomiędzy ingredients a bulleted items
					if(this.IngredientBulletMaxDistance > 0 && ingredientsbulletdistance > 0 && ingredientsbulletdistance > this.IngredientBulletMaxDistance) {
						discoverFirstElementMode = false;
						discoverLastElementMode = false;
						ingredientsbulletdistance = -1;
						lastElementIndex = -1;
						continue;
					}

					//jeśli jest bulleted oznacz jako pierwszy element listy
					if(this.SplittedEvaluation[i].hasBullet) {
						discoverFirstElementMode = false;
						discoverLastElementMode = true;
						ingredientsbulletdistance = -1;
						this.SplittedEvaluation[i].firstElement = true;
						this.SplittedEvaluation[i].listElement = true;
						lastElementIndex = i;
					}
				} else if(discoverLastElementMode) {
					//jeśli nie bulleted oznacz jako ostatni element listy
					if(!this.SplittedEvaluation[i].hasBullet && this.SplittedEntryText[i] && this.SplittedEntryText[i].length > 0) {
						//console.log(this.SplittedEvaluation[lastElementIndex]);
						//console.log(this.SplittedEntryText[lastElementIndex]);
						discoverFirstElementMode = false;
						discoverLastElementMode = false;
						ingredientsbulletdistance = -1;
						if(lastElementIndex != -1) {
							this.SplittedEvaluation[lastElementIndex].lastElement = true;
						}
						lastElementIndex = -1;
					} else if(this.SplittedEvaluation[i].hasBullet) {
						this.SplittedEvaluation[i].listElement = true;
						lastElementIndex = i;
					}
				}
			}
		}

		if(discoverLastElementMode) {
			//składniki są na samym końcu wpisu
			//console.log("lastElement");
			//console.log (this.SplittedEntryText[i - 1]);
			discoverFirstElementMode = false;
			discoverLastElementMode = false;
		}
	};
	/**
	 * sprawdza czy linia zaczyna się od wypunktowania
	 */
	this.evalBullet = function() {
		this.evalRegex(this._BulletRegex, "hasBullet");
	};

	this.evalBulletGroupSize = function() {
		var last = false;
		var groupsize = 0;
		for(var i = 0; i < this.SplittedEvaluation.length; i++) {
			if(this.SplittedEvaluation[i].hasBullet == true) {
				last = true;
				groupsize++;
				this.SplittedEvaluation[i].groupSize = 0;
			} else if(last == true) {
				var j = i - 1;
				while(this.SplittedEvaluation[j].hasBullet == true) {
					this.SplittedEvaluation[j].groupSize = groupsize;
					j--;
					if(j < 0) {
						break;
					}
				}
				last = false;
				groupsize = 0;
			}
		}
	};

	this.evalIngredients = function() {
		this.evalRegex(this._IngredientsRegex, "hasIngredients");
	};

	this.clearItem = function(str) {
		str = str.replace(this._BulletRegex, '');
		str = str.replace(/\s*,$/ig, '');
		str = this.escapeApostrophe(str);

		return str;
	};

	this.escapeApostrophe = function(str) {
		var result = str.replace(/\'/gi, "\\'");
		return result;
	};

	this.hasInnerText = (document.getElementsByTagName("body")[0].innerText != undefined) ? true : false;
	/**
	 *
	 * @param {Object} element
	 */
	this.parseHTMLForText = function(element) {
		var result = "";
		if(element) {
			if(element.nodeType == 1) {
				if(this.hasInnerText) {
					result = element.innerText;
				} else {
					result = element.textContent;
				}
			} else if(element.nodeType == 3) {
				result = element.nodeValue;
			}
		}
		return result;
	};

	this.randomUniqueString = function(str) {

		for(var i = 0; i < 1000; i++) {
			var rndString = this.randomString();

			var index = str.indexOf(rndString);
			if(index < 0) {
				return rndString;
			}
		}

		return null;
	};

	this.randomString = function() {
		var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
		var string_length = 8;
		var randomstring = '';
		for(var i = 0; i < string_length; i++) {
			var rnum = Math.floor(Math.random() * chars.length);
			randomstring += chars.substring(rnum, rnum + 1);
		}
		return randomstring;
	};

	this.getElementsByClassNameL = function(searchClass, node, tag) {
		var classElements = new Array();
		if(node == null)
			node = document;
		if(tag == null)
			tag = '*';

		var els = node.getElementsByTagName(tag);
		var elsLen = els.length;
		var pattern = new RegExp("(^|\\s)" + searchClass + "(\\s|$)");
		for( i = 0, j = 0; i < elsLen; i++) {
			if(pattern.test(els[i].className)) {
				classElements[j] = els[i];
				j++;
			}
		}
		return classElements;
	};

	this.insertAfter = function(currentElement, newElement) {

		var nextObj = currentElement.nextSibling;
		if(nextObj) {
			//console.log("first");
			currentElement.parentNode.insertBefore(newElement, nextObj);
		} else {
			//console.log("second");
			currentElement.parentNode.appendChild(newElement);
		}

	};

	this.insertBefore = function(currentElement, newElement) {
		//console.log("third");
		currentElement.parentNode.insertBefore(newElement, currentElement);
	};

	this.isdefined = function(variable) {
		return ( typeof (window[variable]) == "undefined") ? false : true;
	};

	this.Init();
}

/**
 * BlogProcessor - used to process blog entres searching for specific DOM tree patterns indicating list of ingredient.
 * Once found, ingredients are extracted and Listonic Button is generated next to them.
 */
function BlogProcessor(type) {
	this.type = type;

	this.isIndividualView = false;
	//określa czy jesteśmy w widoku pojedynczego wpisu czy całościowym
	//ma znaczenie przy blox.pl

	this.widgetInfoUrl = "http://listonic.pl/c/cms/blogwidget_about";

	this.buttonsInfoUrl = "http://na1000sposobow.pl/jak-to-dziala/";
	
	
	this.language = typeof listonic_language=="string"?listonic_language:"pl_PL";
	this.language = this.language.toLowerCase();
	
	
	//defines language specific resource eg. texts, images, urls, parameters steering other mechanisms 
	this.resources = {
		pl_PL : {
			themePrefix : "",
			themeSuffix : "",
			howItWorksText : "Jak to działa?",
			howItWorksUrl : "http://na1000sposobow.pl/jak-to-dziala/",
			iWantButtonText : "Chcę taki przycisk",
			iWantButtonUrl : "http://listonic.pl/c/cms/blogwidget_about"
		},
		en_US : {
			themePrefix : "",
			themeSuffix : "_en",
			howItWorksText : "How it works?",
			howItWorksUrl : "http://na1000sposobow.pl/jak-to-dziala/",
			iWantButtonText : "I want button.",
			iWantButtonUrl : "http://listonic.pl/c/cms/blogwidget_about"
			
		}
	}; 
	
	
	this.buttonUrl = "http://buttons.listonic.pl/v1/button.js";
	//this.buttonUrl = "http://hglstudio.com/tp/listotest/button.js";

	this.iframeclass = "listonic_ifrm";
	this.iframeusedclass = "listonic_ifrm_used";

	this.firstOnly = null;
	this.firstOnlyDefined = false;

	this.minCount = 3;
	this.minCountDefined = true;

	this.includeTags = null;
	this.includeTagsDefined = false;

	this.excludeTags = null;
	this.excludeTagsDefined = false;

	this.iframeWidth = null;
	this.iframeWidthDefined = false;

	this.sidebarVisible = true;

	this.listonicButtonIndex = 0;

	this.genericVars = new Array();
	
	/**
	 * functions
	 */
	this.getBlogEntries = null;
	this.checkIfInclude = null;
	this.getEntryContent = null;
	this.getEntryTitle = null;
	this.getEntryUrl = null;

	this.getEntryUrl = null;

	//przyjmuje jako parametr listę uli znalezionych we wpisie a następnie usuwa z nich te które nie powinny być przetwarzane i zwraca
	this.validateULs = null;
	
	this.getResource = function() {
		var resource = this.resources.pl_PL;
	
		if (this.language.substr(0,3) == "en_" || this.language == "en"){
			resource = this.resources.en_US;
		}
		
		return resource;
	};

	//TODO: verify if requried
	this.generateSidebarContentNoIframe = function() {
		var resource = this.getResource();

		var head = document.getElementsByTagName("head");
		if(head && head.length > 0) {

			var link = document.createElement("link");
			link.rel = "stylesheet";
			link.type = "text/css";
			link.href = "http://static.listonic.com/content/buttonPanel/basic"+resource.themeSuffix +".css";

			head[0].appendChild(link);

			document.write('<table class="listonicBox">' + '<tr>' + '<td class="boxL"></td>' + '<td class="boxM">' + '<div class="mainTxt"></div>' + '<div class="buttons">' + '<a href="' + this.resource.howItWorksUrl + '" class="howItWorks">' + resource.iWantButtonText +'</a>' + '<a href="' + resource.iWantButtonUrl + '" class="' + resource.iWantButtonText + '">' + 'Chcę taki przycisk.' + '</a>' + '</div>' + '</td>' + '<td class="boxR"></td>' + '</tr>' + '</table>');
		}

	};

	this.generateSidebarContent = function() {
		var resource = this.getResource();
		
		document.write("<iframe id='listonic_blog_widget' frameborder='0' scrolling='no'> </iframe>");

		var iframe = document.getElementById("listonic_blog_widget");

		var height = 150;
		var width = 175;
		var bgcolor = "#ffffff";
		var theme = "addtoshoppinglist1";

		if(iframe) {
			
			if(this.iframeWidthDefined) {
				width = this.iframeWidth;
			}

			iframe.height = height;
			iframe.width = width;

			var iframeDoc;
			if(iframe.contentDocument) {
				iframeDoc = iframe.contentDocument;
			} else if(iframe.contentWindow) {
				iframeDoc = iframe.contentWindow.document;
			} else if(window.frames[iframe.name]) {
				iframeDoc = window.frames[iframe.name].document;
			}

			if(iframeDoc) {
				iframeDoc.write('<html><head><meta content="text/html; charset=utf-8" http-equiv="Content-Type"><title>Listonic</title><style>body { margin: 0; padding: 0}</style><link rel="stylesheet" type="text/css" href="http://static.listonic.com/content/buttonPanel/basic' + resource.themeSuffix + '.css" />' + '</head><body>' + '<table class="listonicBox">' + '<tr>' + '<td class="boxL"></td>' + '<td class="boxM">' + '<div class="mainTxt"></div>' + '<div class="buttons">' + '<a href="' + resource.howItWorksUrl + '" onclick="javascript: window.parent.location = \'' + resource.howItWorksUrl + '\';" class="howItWorks">' + resource.howItWorksText + '</a>' + '<a href="' + resource.iWantButtonUrl + '" onclick="javascript: window.parent.location = \'' + resource.iWantButtonUrl + '\';" class="iWantButton">'+resource.iWantButtonText+'</a>' + '</div>' + '</td>' + '<td class="boxR"></td>' + '</tr>' + '</table>');

				iframeDoc.write('<\/body><\/html>');

				iframeDoc.close();

			}
		}

	};

	this.Init = function() {
		this.initType();

		if(this.isdefined('listonic_includeTags')) {
			this.includeTags = listonic_includeTags;
			this.includeTagsDefined = true;
		}

		if(this.isdefined('listonic_excludeTags')) {
			this.excludeTags = listonic_excludeTags;
			this.excludeTagsDefined = true;
		}

		if(this.isdefined('listonic_tylkoPierwszy')) {
			this.firstOnly = listonic_tylkoPierwszy;
			this.firstOnlyDefined = true;
		}else if (this.isdefined('listonic_firstOnly')){
			this.firstOnly = listonic_firstOnly;
			this.firstOnlyDefined = true;
		}

		if(this.isdefined('listonic_minIlosc')) {
			this.minCount = parseInt(listonic_minIlosc);
			this.minCountDefined = true;
		}else if(this.isdefined('listonic_minCount')) {
			this.minCount = parseInt(listonic_minCount);
			this.minCountDefined = true;
		}
		
		if(this.isdefined('listonic_iframeWidth')) {

			this.iframeWidth = parseInt(listonic_iframeWidth);
			if(this.iframeWidth && this.iframeWidth > 0) {
				this.iframeWidthDefined = true;
			}
		}

		if(this.isdefined('listonic_ukryjPanelBoczny')) {
			this.sidebarVisible = !Boolean(listonic_ukryjPanelBoczny);
			
		}else if(this.isdefined('listonic_hideSideBar')) {
			this.sidebarVisible = !Boolean(listonic_hideSideBar);
		}

		var do_turnOff = false;
		if(this.isdefined('listonic_turnOff')) {
			do_turnOff = Boolean(listonic_turnOff);
		}

		if(!do_turnOff) {
			if(this.type) {
				if(this.type == "blox") {
					this.initBlox();
				} else if(this.type == "bloog") {
					this.initBloog();
				} else if(this.type == "blogger") {
					this.initBlogger();
				} else if(this.type == "generic") {
					this.initGeneric();
				}

			}
		}

		if(this.sidebarVisible) {
			this.generateSidebarContent();
		}

	};

	this.initType = function() {
		if(this.isdefined('listonic_bw_type')) {
			this.type = listonic_bw_type;
			return;
			//TODO: make it more stupid proof
			//validate choice
		}

		var domain = window.location.hostname;

		if(domain.match(/.*blogspot.com$/ig)) {
			this.type = "blogger"
		} else if(domain.match(/.*blox.pl$/ig)) {
			this.type = "blox";
		} else if(domain.match(/.*bloog.pl$/ig)) {
			this.type = "bloog";
		}
	};

	this.initBlox = function() {
		this.getBlogEntries = this.getBlogEntriesBlox;
		this.checkIfInclude = this.checkIfIncludeBlox;
		this.getEntryContent = this.getEntryContentBlox;
		this.getEntryTitle = this.getEntryTitleBlox;
		this.getEntryUrl = this.getEntryUrlBlox;

		this.validateULs = this.validateULsBlox;
	};

	this.initBloog = function() {
		this.getBlogEntries = this.getBlogEntriesBloog;
		this.checkIfInclude = this.checkIfIncludeBloog;
		this.getEntryContent = this.getEntryContentBloog;
		this.getEntryTitle = this.getEntryTitleBloog;
		this.getEntryUrl = this.getEntryUrlBloog;
	};

	this.initBlogger = function() {
		this.getBlogEntries = this.getBlogEntriesBlogger;
		this.checkIfInclude = this.checkIfIncludeBlogger;
		this.getEntryContent = this.getEntryContentBlogger;
		this.getEntryTitle = this.getEntryTitleBlogger;
		this.getEntryUrl = this.getEntryUrlBlogger;
	};

	this.initGeneric = function() {
		//init content id 
		this.initGenericVar('listonic_bw_generic_contentId', 'contentId');
		//or content class/tag pair
		this.initGenericVar('listonic_bw_generic_contentClass', 'contentClass');
 		this.initGenericVar('listonic_bw_generic_contentTag', 'contentTag');

		this.initGenericVar("listonic_bw_generic_contentAsEntry", 'contentAsEntry');

		this.initGenericVar('listonic_bw_generic_entryClass', 'entryClass');
		this.initGenericVar('listonic_bw_generic_entryTag', 'entryTag');

		this.getBlogEntries = this.getBlogEntriesGeneric;

		this.initGenericVar('listonic_bw_generic_getTags', 'getTags');
		this.checkIfInclude = this.checkIfIncludeGeneric;

		this.initGenericVar('listonic_bw_generic_entryContentClass', 'entryContentClass');
		this.initGenericVar('listonic_bw_generic_entryContentTag', 'entryContentTag');
		this.getEntryContent = this.getEntryContentGeneric;

		this.initGenericVar('listonic_bw_generic_entryHeaderTitleClass', 'entryHeaderTitleClass');
		this.initGenericVar('listonic_bw_generic_entryHeaderTitleTag', 'entryHeaderTitleTag');
		this.getEntryTitle = this.getEntryTitleGeneric;

		this.initGenericVar('listonic_bw_generic_entryHeaderUrlWrapperClass', 'entryHeaderUrlWrapperClass');
		this.initGenericVar('listonic_bw_generic_entryHeaderUrlWrapperTag', 'entryHeaderUrlWrapperTag');
		this.initGenericVar('listonic_bw_generic_entryHeaderUrlClass', 'entryHeaderUrlClass');
		this.getEntryUrl = this.getEntryUrlGeneric;

		if(this.isdefined('listonic_bw_generic_validateULs')) {
			this.validateULs = listonic_bw_generic_validateULs;
		}
	};

	this.initGenericVar = function(generic_var, saveas) {
		if(this.isdefined(generic_var)) {
			this.genericVars[saveas] = eval(generic_var);

		}
	};

	this.process = function() {
		if(this.getBlogEntries) {

			var entries = this.getBlogEntries();

			this.processBlogEntries(entries);
		}
	};

	this.getBlogEntriesBlogger = function() {
		var contentDiv = document.getElementById("Blog1");

		var entries = this.getElementsByClassNameL("post", contentDiv, "div");

		return entries;
	};

	this.getBlogEntriesBloog = function() {

		var contentDiv = document.getElementById("tresc");

		var entries = this.getElementsByClassNameL("wpis", contentDiv, "div");

		//TODO: verify id format

		return entries;
	};

	this.getBlogEntriesBlox = function() {

		var entries = this.getElementsByClassNameL("BlogWpisBox", null, "div");

		if(entries.length <= 0) {
			entries[0] = document.getElementById("SkomentujBox");
			if(entries[0]) {
				this.isIndividualView = true;
			}
		} else {
			this.isIndividualView = false;
		}

		return entries;
	};

	this.getBlogEntriesGeneric = function() {
		var contentCol;
		if(this.IsSet(this.genericVars['contentId'])) {
			contentCol = document.getElementById(this.genericVars['contentId']);
		}else if (this.IsSet(this.genericVars['contentClass'])){
			var elements = this.getElementsByClassNameL(this.genericVars['contentClass'], null, this.genericVars['contentTag']);
			
			if(elements && elements.length > 0) {
				result = elements[0].href;
			}			
			
		}

		var entries = null;

		if(contentCol) {
			if(this.genericVars['contentAsEntry']) {
				entries = new Array();

				entries[0] = contentCol;
				return entries;
			}
		} else {
			contentCol = null;
		}
		entries = this.getElementsByClassNameL(this.genericVars['entryClass'], contentCol, this.genericVars['entryTag']);

		return entries;
	};

	this.processBlogEntries = function(entries) {

		if(entries) {
			if(entries.length > 0) {
				//console.log(entries.length);

				for(var i = 0; i < entries.length; i++) {//TODO: fix
					//console.log(entries[i]);

					//check if suitable for processing
					if(this.checkIfInclude(entries[i])) {

						this.processBlogEntry(entries[i]);
					}

				}
			}
		}
	};

	this.processText = function(content) {
		var tp = new ListonicBlogContentsProcessor(content);

		tp.process();

		if(tp.Lists && tp.Lists.length > 0) {
			return tp.Lists;
		}

	};

	this.processBlogEntry = function(entry) {
		//console.log(entry);

		var entrycontents = this.getEntryContent(entry);

		//console.log(entrycontents);

		if(entrycontents && entrycontents.length > 0) {

			var entrycontent = entrycontents[0];

			var entrytitle = this.getEntryTitle(entry)
			entrytitle = ListonicTrim(entrytitle);

			var entryurl = this.getEntryUrl(entry);

			var uls = entrycontent.getElementsByTagName("ul");

			if(this.validateULs) {
				uls = this.validateULs(entrycontent, uls);
			}

			//uls processing
			if(uls && uls.length > 0) {
				//console.log(uls);

				var tp = null;
				var groupedULS = null;

				//składniki rozbite na kilka sekcji
				//trzeba grupować
				if(uls.length >= 2) {
					tp = new ListonicBlogContentsProcessor(entrycontent);
					groupedULS = tp.processUlsGrouping(uls);

					// nie trzeba grupować
				} else {
					groupedULS = new Array();
					groupedULS[0] = new Array();
					groupedULS[0].push(uls[0]);
				}

				for(var i = 0; i < groupedULS.length; i++) {
					var items = this.processULGroup(groupedULS[i]);
					//console.log(items);
					if(this.hasMinCount(items)) {
						this.generateListonicButton(groupedULS[i][groupedULS[i].length - 1], items, entrytitle, entryurl);
					} else {
						continue;
					}

					if(this.firstOnlyDefined && this.firstOnly === true) {
						break;
					}
				}

				//text processing
			} else {
				//console.log("Texts.Processing");
				var lists = this.processText(entrycontent);
				if(lists) {
					for(var j = 0; j < lists.length; j++) {

						if(lists[j].items && lists[j].lastNode) {

							if(this.hasMinCount(lists[j].items)) {
								this.generateListonicButton(lists[j].lastNode, lists[j].items, entrytitle, entryurl);
							}

						}

					}
				}
			}
		}
	};

	this.getEntryUrlGeneric = function(entry) {
		var result = null;

		if(entry) {

			//TODO : get header first if defined

			var wrapperClass = this.genericVars['entryHeaderTitleClass'];
			var wrapperTag = this.genericVars['entryHeaderTitleTag'];

			var titleElem = this.getElementsByClassNameL(wrapperClass, entry, wrapperTag);

			if(titleElem && titleElem.length > 0) {

				var urlClass = this.genericVars['entryHeaderUrlClass'];

				var alink = null;

				if(urlClass) {
					alink = this.getElementsByClassNameL(urlClass, titleElem[0], 'a');
				} else {
					alink = titleElem[0].getElementsByTagName("a");
				}

				if(alink && alink.length > 0) {
					result = alink[0].href;
				}
			}//else{ result = getEntryUrlFooterGeneric(entry);}

			//todo: get from footer if there is no title
			//dodać w razie zaistnienia potrzeby obsłużenia

		}

		return result;
	}

	this.getEntryUrlBlogger = function(entry) {
		var result = null;

		if(entry) {
			var titleElem = this.getElementsByClassNameL("post-title", entry, "h3");

			if(titleElem && titleElem.length > 0) {

				var alink = titleElem[0].getElementsByTagName("a");

				if(alink && alink.length > 0) {
					result = alink[0].href;
				}
			} else {// nie podano tytułu
				result = this.getEntryUrlFooterBlogger(entry);
			}

		}

		return result;
	};

	this.getEntryUrlFooterBlogger = function(entry) {
		var result = null;
		if(entry) {
			var footer = this.getElementsByClassNameL("post-footer", entry, "div");

			if(footer && footer.length > 0) {
				var timestamp = this.getElementsByClassNameL("post-timestamp", footer[footer.length - 1], "span");

				if(timestamp && timestamp.length > 0) {
					var alink = timestamp[0].getElementsByTagName("a");

					if(alink && alink.length > 0) {
						result = alink[0].href;
					}

				}
			}

		}
		return result;
	};

	this.getEntryUrlBloog = function(entry) {
		var result = null;

		if(entry) {
			var titleElem = entry.getElementsByTagName("h2");

			if(titleElem && titleElem.length > 0) {

				var alink = titleElem[0].getElementsByTagName("a");

				if(alink && alink.length > 0) {
					result = alink[0].href;
				}
			}
		}
		return result;
	};

	this.getEntryUrlBlox = function(entry) {
		var result = null;

		if(entry) {
			var footerElem = this.getElementsByClassNameL("BlogWpisInfo", entry, "div");

			if(footerElem && footerElem.length > 0) {

				var linkElem = this.getElementsByClassNameL("IPTlinkuj", footerElem[0], "a")

				if(linkElem && linkElem.length > 0) {
					result = linkElem[0].href;
				}

			}
		}

		return result;
	};

	this.getEntryTitleBlogger = function(entry) {
		var result = null;

		if(entry) {
			var titleElem = this.getElementsByClassNameL("post-title", entry, "h3");

			if(titleElem && titleElem.length > 0) {
				result = this.parseHTMLForEscapedText(titleElem[0]);
			}

		}

		return result;
	};

	this.getEntryTitleBloog = function(entry) {
		var result = null;

		if(entry) {
			var titleElem = entry.getElementsByTagName("h2");

			if(titleElem && titleElem.length > 0) {
				result = this.parseHTMLForEscapedText(titleElem[0]);
			}
		}

		return result;
	};

	this.getEntryTitleBlox = function(entry) {
		var result = null;
		if(entry) {

			var titleElemClass = "BlogWpisItemTytul";

			if(this.isIndividualView) {
				titleElemClass = "TytulKomentowanegoWpisu";
			}

			var titleElem = this.getElementsByClassNameL(titleElemClass, entry, "div");

			if(titleElem && titleElem.length > 0) {
				result = this.parseHTMLForEscapedText(titleElem[0]);
			}
		}
		return result;
	};

	this.getEntryTitleGeneric = function(entry) {
		var result = null;
		//console.log("getEntryTitleGeneric");
		if(entry) {
			var cssclass = this.genericVars['entryHeaderTitleClass'];
			var tag = this.genericVars['entryHeaderTitleTag'];

			var titleElem = this.getElementsByClassNameL(cssclass, entry, tag);

			if(titleElem && titleElem.length > 0) {
				result = this.parseHTMLForEscapedText(titleElem[0]);

			}
		}

		//console.log(result);
		return result;
	};

	this.getEntryContentBlogger = function(entry) {
		var result = null;
		if(entry) {
			result = this.getElementsByClassNameL("post-body", entry, "div");
		}

		return result;
	};

	this.getEntryContentBloog = function(entry) {
		var result = null;
		if(entry) {
			result = this.getElementsByClassNameL("txt", entry, "div");
		}
		return result;
	};

	this.getEntryContentBlox = function(entry) {
		var result = null;
		if(entry) {
			if(this.isIndividualView) {
				result = this.getElementsByClassNameL("TrescKomentowanegoWpisu", entry, "div");
			} else {
				result = this.getElementsByClassNameL("BlogWpisTresc", entry, "div");
			}
		}
		return result;
	};

	this.getEntryContentGeneric = function(entry) {
		var result = null;
		//console.log(entry);
		if(entry) {

			if(this.IsSet(this.genericVars['entryContentClass']) || this.IsSet(this.genericVars['entryContentTag'])) {
				result = this.getElementsByClassNameL(this.genericVars['entryContentClass'], entry, this.genericVars['entryContentTag']);
			} else {
				//nie ma żadnych informacji nt content zwracaj całe entry
				result = new Array();
				result[0] = entry;
			}
		}
		return result;
	};

	this.checkIfIncludeBlogger = function(entry) {
		var result = true;

		//sprawdĹş czy nie istnieje juĹĽ listonic button
		if(this.hasListonicButton(entry)) {
			return false;
		}

		var tags = this.getTagsBlogger(entry);

		if(this.excludeTagsDefined) {//if exclude tags are defined to not include the button
			var exclude = this.tagsContains(tags, this.excludeTags);

			if(exclude) {
				return false;
			}
		}

		if(this.includeTagsDefined) {// jeĹ›li sÄ… tagi
			var include = this.tagsContains(tags, this.includeTags);
			if(include) {

			} else {
				return false;
			}

		}

		return result;
	};

	this.checkIfIncludeBloog = function(entry) {
		if(this.hasListonicButton(entry)) {
			return false;
		}

		return true;
	};

	this.checkIfIncludeBlox = function(entry) {
		var result = true;

		//sprawdĹş czy nie istnieje juĹĽ listonic button
		if(this.hasListonicButton(entry)) {
			return false;
		}

		var tags = this.getTagsBlox(entry);

		if(this.excludeTagsDefined) {// jeĹ›li sÄ… zdefiniowane tagi wykluczajÄ…ce to nie umieszczaj wpisu przy takim tagu
			var exclude = this.tagsContains(tags, this.excludeTags);

			if(exclude) {
				return false;
			}
		}

		if(this.includeTagsDefined) {// jeĹ›li sÄ… tagi
			var include = this.tagsContains(tags, this.includeTags);
			if(include) {

			} else {
				return false;
			}
		}

		return result;
	};

	this.checkIfIncludeGeneric = function(entry) {
		if(this.hasListonicButton(entry)) {
			return false;
		}

		if(this.IsSet(this.genericVars['getTags'])) {

			var tags = this.genericVars['getTags']();

			if(this.excludeTagsDefined) {// jeśli są zdefiniowane tagi wykluczające to nie umieszczaj wpisu przy takim tagu
				var exclude = this.tagsContains(tags, this.excludeTags);

				if(exclude) {
					return false;
				}
			}

			if(this.includeTagsDefined) {// jeśli są tagi
				var include = this.tagsContains(tags, this.includeTags);
				if(include) {

				} else {
					return false;
				}
			}
		}

		return true;
	};

	this.getTagsBlogger = function(entry) {
		var tags = new Array();

		var entryfooter = this.getElementsByClassNameL("post-footer", entry, "div");
		if(entryfooter && entryfooter.length > 0) {
			var postlabels = this.getElementsByClassNameL("post-labels", entryfooter[0], "span");
			if(postlabels && postlabels.length > 0) {

				var alinks = postlabels[0].getElementsByTagName("a");
				//console.log(alinks);

				if(alinks && alinks.length > 0) {
					for(var i = 0; i < alinks.length; i++) {
						if(alinks[i].rel == 'tag') {
							var buf = alinks[i].innerHTML;
							if(buf) {
								buf = ListonicTrim(buf);
								if(buf.length > 0) {
									tags.push(buf.toLowerCase());
								}
							}
						}
					}
				}
			}

		}

		//console.log("TAGS:");
		//console.log(tags);
		return tags;
	};

	this.getTagsBlox = function(entry) {
		var tags = new Array();

		var infotagi = null;

		if(this.isIndividualView) {
			infotagi = this.getElementsByClassNameL("TagiKomentowanegoWpisu", entry, "div");
		} else {
			var entryinfo = this.getElementsByClassNameL("BlogWpisInfo", entry, "div");
			if(entryinfo && entryinfo.length > 0) {
				infotagi = this.getElementsByClassNameL("infoTagi", entryinfo[0], "div");
			}
		}

		if(infotagi && infotagi.length > 0) {

			var alinks = infotagi[0].getElementsByTagName("a");
			//console.log(alinks);

			if(alinks && alinks.length > 0) {
				for(var i = 0; i < alinks.length; i++) {
					var buf = alinks[i].innerHTML;
					if(buf) {
						buf = ListonicTrim(buf);
						if(buf.length > 0) {
							tags.push(buf.toLowerCase());
						}
					}
				}
			}
		}
		return tags;
	};
	/**
	 * hack dla mojewypieki.blox.pl żeby się nie pojawiało pod socialicons w widoku pojedynczego wpisu
	 * @param {Object} entry
	 * @param {Object} uls
	 */
	this.validateULsBlox = function(entry, uls) {
		if(this.isIndividualView) {
			var result = new Array();

			for(var i = 0; i < uls.length; i++) {
				var isvalid = true;

				var currentNode = uls[i];

				if(currentNode.innerHTML.toLowerCase().indexOf("<input") != -1) {
					isvalid = false;
					break;
				}

				do {
					var parent = currentNode.parentNode;
					currentNode = parent;

					if(parent.className.toLowerCase().indexOf("socialicons") != -1) {
						isvalid = false;
						break;
					}

				} while (parent != entry);

				if(isvalid) {
					result.push(uls[i]);
				}
			}

			return result;
		} else {
			var result = new Array();

			for(var i = 0; i < uls.length; i++) {
				var isvalid = true;

				var currentNode = uls[i];

				if(currentNode.innerHTML.toLowerCase().indexOf("<input") != -1) {
					isvalid = false;
					break;
				}

				if(isvalid) {
					result.push(uls[i]);
				}
			}
			return result;
		}

	}

	this.hasMinCount = function(items) {
		if(this.minCountDefined) {
			if(items && items.length >= this.minCount && items.length > 0) {
				return true;
			} else {
				return false;
			}
		} else {
			if(items && items.length > 0) {
				return true;
			} else {
				return false;
			}
		}
		return true;
	};

	this.hasListonicButton = function(entry) {
		if(entry) {
			var buttons = this.getElementsByClassNameL(this.iframeclass, entry, "iframe");
			if(buttons && buttons.length > 0) {
				return true;
			}
			buttons = this.getElementsByClassNameL(this.iframeusedclass, entry, "iframe");
			if(buttons && buttons.length > 0) {
				return true;
			}
		}
		return false;
	};

	this.processULGroup = function(ulgroup) {
		var items = new Array();

		for(var j = 0; j < ulgroup.length; j++) {
			var ul = ulgroup[j];

			var lis = ul.getElementsByTagName("li");
			if(lis && lis.length > 0) {

				for(var i = 0; i < lis.length; i++) {

					var buf = this.parseHTMLForEscapedText(lis[i]);

					var trimmed = ListonicTrim(buf);
					if(trimmed) {
						items.push(trimmed);
					}
				}

			}
		}

		return items;

	};

	this.processUL = function(ul) {
		var ulElements = new Array();

		var lis = ul.getElementsByTagName("li");
		if(lis && lis.length > 0) {

			for(var i = 0; i < lis.length; i++) {

				var buf = this.parseHTMLForEscapedText(lis[i]);

				var trimmed = ListonicTrim(buf);
				if(trimmed) {
					ulElements.push(trimmed);
				}
			}

		}

		//console.log(ulElements);
		return ulElements;
	};

	this.generateListonicButton = function(ulElement, items, title, url) {
		//console.log("buttons");
		//console.log(items);
		//console.log(ulElement);

		if(ulElement.nodeType == 3 || (ulElement.tagName && ulElement.tagName.toLowerCase() != 'ul')) {
			var br = document.createElement('br');

			this.insertAfter(ulElement, br);
			ulElement = br;
			br = ulElement.cloneNode(false);

			this.insertAfter(ulElement, br);
			ulElement = br;
		}

		var scr1 = document.createElement('script');
		scr1.type = "text/javascript";
		scr1.charset = "UTF-8";
		//scr1.innerHTML = "listonic_content = '";

		//scr1.innerHTML += this.itemsToString(items);

		//scr1.innerHTML += "';";

		var s_listonic_content = "listonic_content_" + this.listonicButtonIndex + " = '";
		s_listonic_content += this.itemsToString(items);
		s_listonic_content += "';";

		if(title) {
			var s_listonic_name = "listonic_name_" + this.listonicButtonIndex + " = '";
			s_listonic_name += title;
			s_listonic_name += "';";
			s_listonic_content += s_listonic_name;
		} else {
			var s_listonic_name = "listonic_name_" + this.listonicButtonIndex + " = '';";
			s_listonic_content += s_listonic_name;
		}

		if(url) {
			var s_listonic_url = "listonic_url_" + this.listonicButtonIndex + " = '";
			s_listonic_url += url;
			s_listonic_url += "';";
			s_listonic_content += s_listonic_url;
		} else {
			var s_listonic_url = "listonic_url_" + this.listonicButtonIndex + " = '';";
			s_listonic_content += s_listonic_url;
		}

		if(document.all) {//IE
			scr1.text = s_listonic_content;

		} else {//rest
			scr1.innerHTML = s_listonic_content;
			scr1.innerText = s_listonic_content;
		}

		this.insertAfter(ulElement, scr1);

		var ifrm1 = document.createElement("iframe");

		ifrm1.className = this.iframeclass;
		ifrm1.frameBorder = "0";
		ifrm1.scrolling = "no";
		ifrm1.id = this.iframeclass + "_" + this.listonicButtonIndex;

		this.insertAfter(scr1, ifrm1);

		var scr2 = document.createElement("script");
		scr2.charset = "UTF-8";
		scr2.type = "text/javascript";
		scr2.src = this.buttonUrl;

		this.insertAfter(ifrm1, scr2);

		var br = document.createElement('br');

		this.insertAfter(scr2, br);

		this.listonicButtonIndex++;
	};

	this.itemsToString = function(items) {
		for (var i=0; i<items.length; i++) {
            items[i] = items[i].replace(/\n/i,"");
        }
		
		var lastItem = items.pop();
		var result = "";
		for(var i = 0; i < items.length; i++) {
			result += items[i] + " <br /> ";
		}
		result += lastItem;
		return result;
	};

	this.insertAfter = function(currentElement, newElement) {

		var nextObj = currentElement.nextSibling;

		if(nextObj) {
			currentElement.parentNode.insertBefore(newElement, nextObj);
		} else {
			currentElement.parentNode.appendChild(newElement);
		}

	};

	this.getElementsByClassNameL = function(searchClass, node, tag) {

		var classElements = new Array();
		if(node == null)
			node = document;

		if(searchClass == null) {
			if(tag != null)
				var result = node.getElementsByTagName(tag);

			return result;
		}

		if(tag == null)
			tag = '*';

		var els = node.getElementsByTagName(tag);
		var elsLen = els.length;
		var pattern = new RegExp("(^|\\s)" + searchClass + "(\\s|$)");
		for( i = 0, j = 0; i < elsLen; i++) {
			if(pattern.test(els[i].className)) {
				classElements[j] = els[i];
				j++;
			}
		}
		return classElements;
	};

	this.arrayContains = function(array, value) {
		var i = array.length;
		while(i--) {
			if(array[i] === value) {
				return true;
			}
		}
		return false;
	};

	this.tagsContains = function(tags, matches) {
		if(tags && matches) {
			var i = matches.length;
			while(i--) {
				if(this.arrayContains(tags, matches[i])) {
					return true;
				}
			}
		}
		return false;
	};
	/*
	 // /////////
	 // isdefined v1.0
	 //
	 // Check if a javascript variable has been defined.
	 //
	 // Author : Jehiah Czebotar
	 // Website: http://www.jehiah.com
	 // Usage  : alert(isdefined('myvar'));
	 // /////////
	 */
	this.isdefined = function(variable) {
		return ( typeof (window[variable]) == "undefined") ? false : true;
	};
	
	/**
	 * innerText
	 *
	 */
	this.hasInnerText = (document.getElementsByTagName("body")[0].innerText != undefined) ? true : false;

	this.parseHTMLForEscapedText = function(element) {
		var result = "";

		if(element) {
			if(this.hasInnerText) {
				result = element.innerText;
			} else {
				result = element.textContent;
			}
		}

		if(result) {
			result = this.escapeApostrophe(result);
		}

		return result;
	};

	this.parseHTMLForText = function(element) {
		var result = "";
		if(element) {
			if(element.nodeType == 1) {

				if(this.hasInnerText) {
					result = element.innerText;
				} else {
					result = element.textContent;
				}
			} else if(element.nodeType == 3) {
				result = element.nodeValue;
			}
		}
		return result;
	};

	this.escapeApostrophe = function(str) {
		var result = str.replace(/\'/gi, "\\'");
		return result;
	};

	this.IsSet = function(variable) {
		return ( typeof (variable) != 'undefined');
	};
}

var ListonicBlogWidgetInstance = new BlogProcessor("blogger");
ListonicBlogWidgetInstance.Init();
ListonicBlogWidgetInstance.process();

var ListonicEventDocumentReady = (function(){    

    var readyList,
        DOMContentLoaded,
        class2type = {};
        class2type["[object Boolean]"] = "boolean";
        class2type["[object Number]"] = "number";
        class2type["[object String]"] = "string";
        class2type["[object Function]"] = "function";
        class2type["[object Array]"] = "array";
        class2type["[object Date]"] = "date";
        class2type["[object RegExp]"] = "regexp";
        class2type["[object Object]"] = "object";

    var ReadyObj = {
        // Is the DOM ready to be used? Set to true once it occurs.
        isReady: false,
        // A counter to track how many items to wait for before
        // the ready event fires. See #6781
        readyWait: 1,
        // Hold (or release) the ready event
        holdReady: function( hold ) {
            if ( hold ) {
                ReadyObj.readyWait++;
            } else {
                ReadyObj.ready( true );
            }
        },
        // Handle when the DOM is ready
        ready: function( wait ) {
            // Either a released hold or an DOMready/load event and not yet ready
            if ( (wait === true && !--ReadyObj.readyWait) || (wait !== true && !ReadyObj.isReady) ) {
                // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
                if ( !document.body ) {
                    return setTimeout( ReadyObj.ready, 1 );
                }

                // Remember that the DOM is ready
                ReadyObj.isReady = true;
                // If a normal DOM Ready event fired, decrement, and wait if need be
                if ( wait !== true && --ReadyObj.readyWait > 0 ) {
                    return;
                }
                // If there are functions bound, to execute
                readyList.resolveWith( document, [ ReadyObj ] );

                // Trigger any bound ready events
                //if ( ReadyObj.fn.trigger ) {
                //  ReadyObj( document ).trigger( "ready" ).unbind( "ready" );
                //}
            }
        },
        bindReady: function() {
            if ( readyList ) {
                return;
            }
            readyList = ReadyObj._Deferred();

            // Catch cases where $(document).ready() is called after the
            // browser event has already occurred.
            if ( document.readyState === "complete" ) {
                // Handle it asynchronously to allow scripts the opportunity to delay ready
                return setTimeout( ReadyObj.ready, 1 );
            }

            // Mozilla, Opera and webkit nightlies currently support this event
            if ( document.addEventListener ) {
                // Use the handy event callback
                document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
                // A fallback to window.onload, that will always work
                window.addEventListener( "load", ReadyObj.ready, false );

            // If IE event model is used
            } else if ( document.attachEvent ) {
                // ensure firing before onload,
                // maybe late but safe also for iframes
                document.attachEvent( "onreadystatechange", DOMContentLoaded );

                // A fallback to window.onload, that will always work
                window.attachEvent( "onload", ReadyObj.ready );

                // If IE and not a frame
                // continually check to see if the document is ready
                var toplevel = false;

                try {
                    toplevel = window.frameElement == null;
                } catch(e) {}

                if ( document.documentElement.doScroll && toplevel ) {
                    doScrollCheck();
                }
            }
        },
        _Deferred: function() {
            var // callbacks list
                callbacks = [],
                // stored [ context , args ]
                fired,
                // to avoid firing when already doing so
                firing,
                // flag to know if the deferred has been cancelled
                cancelled,
                // the deferred itself
                deferred  = {

                    // done( f1, f2, ...)
                    done: function() {
                        if ( !cancelled ) {
                            var args = arguments,
                                i,
                                length,
                                elem,
                                type,
                                _fired;
                            if ( fired ) {
                                _fired = fired;
                                fired = 0;
                            }
                            for ( i = 0, length = args.length; i < length; i++ ) {
                                elem = args[ i ];
                                type = ReadyObj.type( elem );
                                if ( type === "array" ) {
                                    deferred.done.apply( deferred, elem );
                                } else if ( type === "function" ) {
                                    callbacks.push( elem );
                                }
                            }
                            if ( _fired ) {
                                deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
                            }
                        }
                        return this;
                    },

                    // resolve with given context and args
                    resolveWith: function( context, args ) {
                        if ( !cancelled && !fired && !firing ) {
                            // make sure args are available (#8421)
                            args = args || [];
                            firing = 1;
                            try {
                                while( callbacks[ 0 ] ) {
                                    callbacks.shift().apply( context, args );//shifts a callback, and applies it to document
                                }
                            }
                            finally {
                                fired = [ context, args ];
                                firing = 0;
                            }
                        }
                        return this;
                    },

                    // resolve with this as context and given arguments
                    resolve: function() {
                        deferred.resolveWith( this, arguments );
                        return this;
                    },

                    // Has this deferred been resolved?
                    isResolved: function() {
                        return !!( firing || fired );
                    },

                    // Cancel
                    cancel: function() {
                        cancelled = 1;
                        callbacks = [];
                        return this;
                    }
                };

            return deferred;
        },
        type: function( obj ) {
            return obj == null ?
                String( obj ) :
                class2type[ Object.prototype.toString.call(obj) ] || "object";
        }
    }
    // The DOM ready check for Internet Explorer
    function doScrollCheck() {
        if ( ReadyObj.isReady ) {
            return;
        }

        try {
            // If IE is used, use the trick by Diego Perini
            // http://javascript.nwbox.com/IEContentLoaded/
            document.documentElement.doScroll("left");
        } catch(e) {
            setTimeout( doScrollCheck, 1 );
            return;
        }

        // and execute any waiting functions
        ReadyObj.ready();
    }
    // Cleanup functions for the document ready method
    if ( document.addEventListener ) {
        DOMContentLoaded = function() {
            document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
            ReadyObj.ready();
        };

    } else if ( document.attachEvent ) {
        DOMContentLoaded = function() {
            // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
            if ( document.readyState === "complete" ) {
                document.detachEvent( "onreadystatechange", DOMContentLoaded );
                ReadyObj.ready();
            }
        };
    }
    function ready( fn ) {
        // Attach the listeners
        ReadyObj.bindReady();

        var type = ReadyObj.type( fn );

        // Add the callback
        readyList.done( fn );//readyList is result of _Deferred()
    }
    return ready;
})();

ListonicEventDocumentReady(function() {
	ListonicBlogWidgetInstance.process();
});